// WebSocket连接工具类
import { getToken } from "@/utils/auth";

// 定义类型接口
interface WebSocketMessage {
  type: string;
  [key: string]: any;
}

interface BindSuccessMessage extends WebSocketMessage {
  type: "bind_success";
  message: string;
  organization_id: number;
  organization_type: string;
}

interface NotificationPayload {
  title: string;
  message: string;
  sound?: string;
  route?: string;
  payload?: Record<string, any> | null;
  messageId?: number;
  recipientId?: number;
  targetId?: number;
  targetType?: string;
  attempt?: number;
  raw?: Record<string, any> | null;
}

interface SystemNotificationMessage extends WebSocketMessage {
  type: "notification";
  data?: NotificationPayload;
  title?: string;
  content?: string;
  message?: string;
  route?: string;
  payload?: Record<string, any> | null;
  sound?: string;
}

interface NotificationOptions {
  title: string;
  message: string;
  route?: string;
  sound?: string;
  messageId?: number;
  recipientId?: number;
  targetId?: number;
  targetType?: string;
  attempt?: number;
}

class WebSocketClient {
  private ws: WebSocket | null = null;
  private url: string = "";
  private connected: boolean = false;
  private reconnectInterval: number = 5000; // 重连间隔(毫秒)
  private heartbeatInterval: number = 30000; // 心跳间隔(毫秒)
  private heartbeatTimer: number | null = null;
  private reconnectTimer: number | null = null;
  private callbacks: { [key: string]: Function } = {};
  private notificationProcessed: Set<string> = new Set(); // 防止重复处理通知
  private bindRetryTimer: number | null = null;
  private bindAttempts = 0;

  // 初始化WebSocket连接
  init(): void {
    // 防止重复初始化
    if (this.ws && this.connected) {
      console.log("WebSocket已经连接，无需重复初始化");
      return;
    }

    const wsHost = import.meta.env.VITE_WEBSOCKET_HOST || "ws://127.0.0.1:2348";
    this.url = wsHost;
    this.connect();
  }

  // 建立连接
  connect(): void {
    try {
      // 如果已有连接，先关闭
      if (this.ws) {
        this.close();
      }

      this.ws = new WebSocket(this.url);

      this.ws.onopen = () => {
        console.log("WebSocket连接已建立");
        this.connected = true;
        this.clearReconnectTimer();
        this.startHeartbeat();

        // 连接成功后绑定用户
        this.bindUser();
      };

      this.ws.onmessage = (event: MessageEvent) => {
        this.handleMessage(event.data);
      };

      this.ws.onclose = () => {
        console.log("WebSocket连接已断开");
        this.connected = false;
        this.stopHeartbeat();
        this.scheduleReconnect();
      };

      this.ws.onerror = (error: Event) => {
        console.error("WebSocket发生错误:", error);
        this.stopHeartbeat();
      };
    } catch (error) {
      console.error("WebSocket连接失败:", error);
      this.scheduleReconnect();
    }
  }

  // 绑定用户（传递token和hashid）
  bindUser(): void {
    const token = getToken();
    if (!token?.accessToken) {
      console.warn("未找到accessToken，等待刷新后重试");
      this.scheduleBindRetry();
      return;
    }

    this.clearBindRetry();
    this.send({
      type: "bind",
      accesstoken: token.accessToken
    });
  }

  // 处理接收到的消息
  handleMessage(data: string): void {
    try {
      const message: WebSocketMessage = JSON.parse(data);

      switch (message.type) {
        case "ping":
          // 心跳响应
          break;
        case "bind_success":
          // 绑定成功响应
          console.log("用户绑定成功:", (message as BindSuccessMessage).message);
          this.clearBindRetry();
          this.bindAttempts = 0;
          break;
        case "bind_error":
          console.log("用户绑定失败:", (message as BindSuccessMessage).message);
          this.scheduleBindRetry();
          break;
        case "notification": {
          console.log("收到系统通知:", message);
          const payload = this.normaliseNotificationPayload(
            message as SystemNotificationMessage
          );
          if (payload) {
            this.handleSystemNotification(payload);
          } else {
            console.warn("无法解析系统通知:", message);
          }
          break;
        }
        default:
          // 其他类型消息
          if (this.callbacks[message.type]) {
            this.callbacks[message.type](message);
          }
      }
    } catch (error) {
      console.error("处理WebSocket消息失败:", error);
    }
  }

  private normaliseNotificationPayload(
    message: SystemNotificationMessage
  ): NotificationPayload | null {
    const ensureNumber = (value: unknown): number | undefined => {
      if (typeof value === "number" && Number.isFinite(value)) {
        return value;
      }
      if (typeof value === "string" && value.trim() !== "") {
        const parsed = Number(value);
        if (Number.isFinite(parsed)) {
          return parsed;
        }
      }
      return undefined;
    };

    const data = message?.data;
    const rawTitle =
      data?.title ??
      message.title ??
      message.message ??
      (typeof message?.payload === "object"
        ? (message.payload as Record<string, any>)?.title
        : undefined);

    const rawContent =
      data?.message ??
      message.message ??
      message.content ??
      (typeof message?.payload === "object"
        ? ((message.payload as Record<string, any>)?.message ??
          (message.payload as Record<string, any>)?.content)
        : undefined);

    const rawPayload =
      typeof message?.payload === "object" && message.payload !== null
        ? (message.payload as Record<string, any>)
        : null;

    const route =
      data?.route ??
      message.route ??
      (typeof message?.payload === "object"
        ? (message.payload as Record<string, any>)?.route
        : undefined);

    const sound = data?.sound ?? message.sound;
    const payload = data?.payload ?? (rawPayload ? { ...rawPayload } : null);

    const title = rawTitle ?? "";
    const content = rawContent ?? "";

    if (!title && !content && !route) {
      return null;
    }

    const messageId =
      ensureNumber((message as Record<string, any>)?.message_id) ??
      ensureNumber((data as Record<string, any>)?.message_id) ??
      (payload
        ? ensureNumber((payload as Record<string, any>)?.message_id)
        : undefined);

    const recipientId =
      ensureNumber((message as Record<string, any>)?.recipient_id) ??
      ensureNumber((data as Record<string, any>)?.recipient_id) ??
      (payload
        ? ensureNumber((payload as Record<string, any>)?.recipient_id)
        : undefined);

    const targetId =
      ensureNumber((message as Record<string, any>)?.target_id) ??
      ensureNumber((data as Record<string, any>)?.target_id) ??
      (payload
        ? ensureNumber((payload as Record<string, any>)?.target_id)
        : undefined);

    const targetType =
      (data as Record<string, any>)?.target_type ??
      (message as Record<string, any>)?.target_type ??
      (payload as Record<string, any> | null)?.target_type;

    const attemptValue =
      ensureNumber((message as Record<string, any>)?.attempt) ??
      ensureNumber((data as Record<string, any>)?.attempt) ??
      (payload
        ? ensureNumber((payload as Record<string, any>)?.attempt)
        : undefined);

    return {
      title: title,
      message: content,
      sound,
      route,
      payload,
      messageId,
      recipientId,
      targetId,
      targetType,
      attempt: attemptValue,
      raw: rawPayload
    };
  }

  // 处理系统通知
  handleSystemNotification(data: NotificationPayload): void {
    if (!data) return;
    // 生成通知的唯一标识，防止重复处理
    const attemptKey =
      data.attempt !== undefined && data.attempt !== null
        ? `attempt-${data.attempt}`
        : "";

    const notificationId =
      data.messageId !== undefined
        ? `message-${data.messageId}-${data.recipientId ?? ""}-${attemptKey}`
        : `${data.title ?? ""}-${data.message ?? ""}-${Date.now()}-${Math.random()}`;
    if (this.notificationProcessed.has(notificationId)) {
      console.log("重复通知，已忽略:", data);
      return;
    }

    // 添加到已处理集合
    this.notificationProcessed.add(notificationId);

    // 限制集合大小，避免内存泄漏
    if (this.notificationProcessed.size > 100) {
      const iterator = this.notificationProcessed.values();
      this.notificationProcessed.delete(iterator.next().value);
    }

    // 如果是重要通知，显示系统通知并播放声音
    const soundUrl =
      data.sound || "https://static.bcbiz.com/system/message.wav";

    const notificationOptions: NotificationOptions = {
      title: data.title,
      message: data.message,
      route: data.route,
      sound: soundUrl,
      attempt: data.attempt
    };
    window.electronAPI?.showNotification?.({
      ...notificationOptions,
      messageId: data.messageId,
      recipientId: data.recipientId,
      targetId: data.targetId,
      targetType: data.targetType
    });

    // 触发通知更新事件
    window.dispatchEvent(
      new CustomEvent("systemNotification", {
        detail: {
          ...data,
          sound: soundUrl
        }
      })
    );
  }

  // 发送消息
  send(data: WebSocketMessage): void {
    if (this.connected && this.ws?.readyState === WebSocket.OPEN) {
      this.ws.send(JSON.stringify(data));
    } else {
      console.warn("WebSocket未连接，消息发送失败:", data);
    }
  }

  // 开始心跳
  startHeartbeat(): void {
    this.heartbeatTimer = window.setInterval(() => {
      this.send({ type: "ping" });
    }, this.heartbeatInterval);
  }

  // 停止心跳
  stopHeartbeat(): void {
    if (this.heartbeatTimer) {
      window.clearInterval(this.heartbeatTimer);
      this.heartbeatTimer = null;
    }
  }

  // 安排重连
  scheduleReconnect(): void {
    this.clearReconnectTimer();
    this.reconnectTimer = window.setTimeout(() => {
      console.log("尝试重新连接WebSocket...");
      this.connect();
    }, this.reconnectInterval);
  }

  private scheduleBindRetry(): void {
    if (!this.connected || this.ws?.readyState !== WebSocket.OPEN) return;
    this.clearBindRetry();

    const delay = Math.min(30000, 5000 * Math.max(1, this.bindAttempts));
    this.bindRetryTimer = window.setTimeout(() => {
      this.bindAttempts += 1;
      this.bindUser();
    }, delay);
  }

  private clearBindRetry(): void {
    if (this.bindRetryTimer) {
      window.clearTimeout(this.bindRetryTimer);
      this.bindRetryTimer = null;
    }
  }

  // 清除重连定时器
  clearReconnectTimer(): void {
    if (this.reconnectTimer) {
      window.clearTimeout(this.reconnectTimer);
      this.reconnectTimer = null;
    }
  }

  // 注册消息回调
  on(type: string, callback: Function): void {
    this.callbacks[type] = callback;
  }

  // 关闭连接
  close(): void {
    this.clearReconnectTimer();
    this.clearBindRetry();
    this.stopHeartbeat();

    if (this.ws) {
      this.ws.close();
      this.ws = null;
    }

    this.connected = false;
    // 清空已处理的通知记录
    this.notificationProcessed.clear();
  }
}

// 创建单例实例
const websocketClient = new WebSocketClient();

export default websocketClient;
